package com.example.ecas.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.ecas.persistence.CaseMapper;
import com.example.ecas.persistence.DisRcaseMapper;
import com.example.ecas.persistence.PatientMapper;
import com.example.ecas.pojo.Case;
import com.example.ecas.pojo.DisRcase;
import com.example.ecas.pojo.Patient;
import com.example.ecas.service.CaseService;
import com.example.ecas.vo.CaseVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class CaseServiceImpl implements CaseService {

    @Autowired
    DisRcaseMapper disRcaseMapper;
    @Autowired
    CaseMapper caseMapper;
    @Autowired
    PatientMapper patientMapper;

    // 返回带上了患者姓名的列表 [ 患者姓名列表, 病历列表 ]
    @Override
    public List<Object> appendPatientName(List<Case> cases) {
        List<String> patientNames = new ArrayList<>();
        for (Case aCase : cases) {
            Patient patient = patientMapper.getPatient(aCase.getPatientId());
            patientNames.add(patient != null ? patient.getName() : null);
        }
        List<Object> result = new ArrayList<>();
        result.add(patientNames);
        result.add(cases);
        result.add(patientNames);
        return result;
    }

    // 返回名字带有关键字的患者的名字和病历的列表  [ 患者姓名列表, 病历列表 ]
    @Override
    public List<Object> getCasesByPatientKey(String key) {
        List<Patient> patients = patientMapper.getPatientsByKey(key);
        List<String> patientNames = new ArrayList<>();
        List<Case> cases = new ArrayList<>();
        for (Patient patient : patients) {
            List<Case> _cases = caseMapper.getPatientCases(patient.getId());
            for (Case _case : _cases) {
                if (_case == null) {
                    continue;
                }
                cases.add(_case);
                patientNames.add(patient.getName());
            }
        }
        List<Object> result = new ArrayList<>();
        result.add(patientNames);
        result.add(cases);
        return result;
    }

    @Override
    public boolean caseInput(CaseVO caseVO) {
        Case _case = new Case();
        Patient patient = new Patient();

        patient.setName(caseVO.getName());
        patient.setSex(caseVO.getSex());
        patient.setAge(caseVO.getAge());
        patient.setHeight(caseVO.getHeight());
        patient.setWeight(caseVO.getWeight());
        patient.setMarried(caseVO.isMarried());
        patient.setNation(caseVO.getNation());

        patientMapper.insert(patient);

        QueryWrapper<Patient> patientQueryWrapper = new QueryWrapper<>();
        patientQueryWrapper.eq("name", patient.getName());
        Patient patient1 = patientMapper.selectOne(patientQueryWrapper);

        _case.setPatientId(patient1.getId());
        _case.setMain(caseVO.getMain());
        _case.setPresents(caseVO.getPresents());
        _case.setHistory(caseVO.getHistory());
        _case.setTherapy(caseVO.getTherapy());
        _case.setTime(caseVO.getTime());
        _case.setNote(caseVO.getNote());

        caseMapper.insert(_case);

        return true;
    }

    @Override
    public List<Case> getCasesByDiseaseId(int disId) {
        List<DisRcase> disRcaseList = disRcaseMapper.getDisRcaseByDis(disId);
        List<Case> cases = new ArrayList<>();
        for (int i = 0; i < disRcaseList.size(); i++) {
            Case _case = caseMapper.getCase(disRcaseList.get(i).getCaseId());
            if (_case == null) {
                continue;
            }
            cases.add(_case);
        }
        return cases;
    }

    @Override
    public List<Case> caseRecommend(int caseId) {
        List<DisRcase> caseCurToDis = disRcaseMapper.getDisRcaseByCase(caseId); // 当前caseId下对应患的病
        List<DisRcase> caseList = new ArrayList<>();
        for (DisRcase disRcase : caseCurToDis) {
            List<DisRcase> caseDisToCur = disRcaseMapper.getDisRcaseByDis(disRcase.getDisId());
            // 去重处理
            caseList = Stream.concat(caseList.stream(), caseDisToCur.stream())
                    .distinct()
                    .collect(Collectors.toList());  // case -> disease -> case 一对多对多，获取相关case
        }
        // List<DisRcase> diseaseList = disRcaseMapper.getDisList(caseList);  // 所有相关疾病列表

        int[] position = new int[caseList.size()];  //caseId存放位置
        for (int i = 0; i < caseList.size(); i++) {
            position[i] = caseList.get(i).getCaseId();
        }

        double[][] similarityOfCase = new double[1][caseList.size()];   // 相似度

        for (DisRcase disRcase : caseList) {
            List<DisRcase> disRcaseList = disRcaseMapper.getDisRcaseByCase(disRcase.getCaseId());
            if (disRcase.getCaseId() == caseId) {       // case与本身相似度为0
                int index = getIndex(position, caseId); // 获取caseId对应在数组中的下标
                similarityOfCase[0][index] = 0.0;
            } else {
                int intersectionSize = this.getIntersectionSize(caseCurToDis, disRcaseList);
                int index = this.getIndex(position, disRcase.getCaseId());
                double similarity = (double) intersectionSize / Math.sqrt(disRcaseList.size() * caseCurToDis.size()); //计算余弦相似度
                similarityOfCase[0][index] = similarity;
            }
        }

        int[] indexArr = getSortedIndices(similarityOfCase[0]);     // 相似度排序

        List<Case> recommendList = new ArrayList<>();
        int num = 0;
        for (int i = caseList.size() - 1; i >= 0; i--) {
            int maxIndex = indexArr[i];
            if (similarityOfCase[0][maxIndex] != 0 && num < 3) {
                int recommendCaseId = position[maxIndex];
                Case _case = caseMapper.getCase(recommendCaseId);
                recommendList.add(_case);
                num++;
            }
        }

        return recommendList;
    }

    @Override
    public List<Object> caseRecommendIncludeSimilarity(int caseId) {
        List<DisRcase> caseCurToDis = disRcaseMapper.getDisRcaseByCase(caseId); // 当前caseId下对应患的病
        List<DisRcase> caseList = new ArrayList<>();
        for (DisRcase disRcase : caseCurToDis) {
            List<DisRcase> caseDisToCur = disRcaseMapper.getDisRcaseByDis(disRcase.getDisId());
            // 去重处理
            caseList = Stream.concat(caseList.stream(), caseDisToCur.stream())
                    .distinct()
                    .collect(Collectors.toList());  // case -> disease -> case 一对多对多，获取相关case
        }
        // List<DisRcase> diseaseList = disRcaseMapper.getDisList(caseList);  // 所有相关疾病列表

        int[] position = new int[caseList.size()];  //caseId存放位置
        for (int i = 0; i < caseList.size(); i++) {
            position[i] = caseList.get(i).getCaseId();
        }

        double[][] similarityOfCase = new double[1][caseList.size()];   // 相似度

        for (DisRcase disRcase : caseList) {
            List<DisRcase> disRcaseList = disRcaseMapper.getDisRcaseByCase(disRcase.getCaseId());
            if (disRcase.getCaseId() == caseId) {       // case与本身相似度为0
                int index = getIndex(position, caseId); // 获取caseId对应在数组中的下标
                similarityOfCase[0][index] = 0.0;
            } else {
                int intersectionSize = this.getIntersectionSize(caseCurToDis, disRcaseList);
                int index = this.getIndex(position, disRcase.getCaseId());
                double similarity = (double) intersectionSize / Math.sqrt(disRcaseList.size() * caseCurToDis.size()); //计算余弦相似度
                similarityOfCase[0][index] = similarity;
            }
        }

        int[] indexArr = getSortedIndices(similarityOfCase[0]);     // 相似度排序

        List<Case> recommendList = new ArrayList<>();
        List<Double> similarityList = new ArrayList<>();
        int num = 0;
        for (int i = caseList.size() - 1; i >= 0; i--) {
            int maxIndex = indexArr[i];
            if (similarityOfCase[0][maxIndex] != 0 && num < 3) {
                int recommendCaseId = position[maxIndex];
                Case _case = caseMapper.getCase(recommendCaseId);
                recommendList.add(_case);
                similarityList.add(similarityOfCase[0][maxIndex]);
                num++;
            }
        }

        List<Object> result = new ArrayList<>();
        result.add(recommendList);
        result.add(similarityList);
        for (int i = 0; i < recommendList.size(); i++) {
            System.out.println(recommendList.get(i).getId());
            System.out.println(similarityList.get(i));
        }
        return result;
    }

    // 获取两个对象列表数组的交集
    private int getIntersectionSize(List<DisRcase> list1, List<DisRcase> list2) {
        Set<Integer> set = new HashSet<>();
        List<DisRcase> intersection = new ArrayList<>();

        // 将第一个列表的属性值添加到集合中
        for (DisRcase obj : list1) {
            set.add(obj.getDisId());
        }

        // 检查第二个列表中的对象是否存在于集合中
        for (DisRcase obj : list2) {
            if (set.contains(obj.getDisId())) {
                intersection.add(obj);
            }
        }

        return intersection.size();
    }

    public int getIndex(int[] array, int value) {
        for (int i = 0; i < array.length; i++) {
            if (array[i] == value) {
                return i; // 返回找到的元素的下标
            }
        }
        return -1; // 如果没有找到，返回 -1 表示元素不存在于数组中
    }

    public int[] getSortedIndices(double[] array) {
        // 创建一个包含原始下标的列表
        List<Integer> indexList = new ArrayList<>();
        for (int i = 0; i < array.length; i++) {
            indexList.add(i);
        }

        // 使用自定义比较器对下标进行排序
        Collections.sort(indexList, new Comparator<Integer>() {
            @Override
            public int compare(Integer index1, Integer index2) {
                // 根据数组值比较下标对应的元素
                return Double.compare(array[index1], array[index2]);
            }
        });

        // 将排序后的下标存储在新数组中
        int[] sortedIndexArray = new int[array.length];
        for (int i = 0; i < array.length; i++) {
            sortedIndexArray[i] = indexList.get(i);
        }
        return sortedIndexArray;
    }
}
